use bevy::{
    math::Mat4,
    transform::components::{GlobalTransform, Transform},
};

use crate::{pipeline::BillboardUniform, BillboardLockAxis};

// TODO: Maybe add scale as uniform to shader and do this in shader?
/// 计算一个没有旋转信息的变换矩阵。
///
/// # 参数
///
/// - `global_transform`: 表示物体的全局变换（`GlobalTransform`）。提供物体在世界坐标系中的位置、旋转和缩放信息。
/// - `transform`: 表示物体的本地变换（`Transform`）。提供物体的本地缩放数据。
///
/// # 返回值
/// 返回一个 `Mat4` 矩阵，其中包含保留缩放和位置信息但移除了旋转的变换数据。
///
/// # 说明
///
/// 1. `global_transform.compute_matrix()` 会计算物体的完整全局变换矩阵（带有位置、旋转、缩放）。
/// 2. 使用 `Mat4::from_cols` 函数重新生成一个矩阵，将缩放应用到轴向数据上，但移除旋转效果。
/// 3. 位置信息（`w_axis`）直接保留来源自全局变换，确保物体以正确的位置展示。
///
/// 这种方式对广告牌很有用，因为我们通常希望广告牌仅保留缩放和位置，而不是旋转。
pub fn compute_matrix_without_rotation(
    global_transform: &GlobalTransform,
    transform: &Transform,
) -> Mat4 {
    let global_matrix = global_transform.compute_matrix();
    // dbg!(transform.scale);
    Mat4::from_cols(
        Mat4::IDENTITY.x_axis * transform.scale.x,
        Mat4::IDENTITY.y_axis * transform.scale.y,
        Mat4::IDENTITY.z_axis * transform.scale.z,
        global_matrix.w_axis,
    )
}

/// 计算广告牌的 World 矩阵，并根据是否锁定轴的设定调整输出。
///
/// # 参数
/// - `global_transform`: 对应物体的全局变换（GlobalTransform）。
/// - `transform`: 对应物体的本地变换（Transform），用以获取缩放信息。
/// - `lock_axis`: 可选参数，用于控制广告牌是否锁定某些轴，例如 Y 轴或旋转轴。
///
/// # 返回值
/// 返回一个 `BillboardUniform`，其中包含广告牌的变换矩阵。
/// 当 `lock_axis` 被指定时，使用全局变换矩阵。
/// 否则，去除旋转信息，保持缩放和位置。
///
/// # 注意
/// 如果 `lock_axis` 参数不为 `None`，广告牌将忽略旋转，否则会计算一个无旋转的矩阵。
pub fn calculate_billboard_uniform(
    global_transform: &GlobalTransform,
    transform: &Transform,
    lock_axis: Option<&BillboardLockAxis>,
) -> BillboardUniform {
    // 检查是否需要锁定轴，如果需要则直接使用全局变换矩阵；否则，去除旋转信息。
    let transform = if lock_axis.is_some() {
        global_transform.compute_matrix()
    } else {
        compute_matrix_without_rotation(global_transform, transform)
    };

    // 返回包含计算后变换矩阵的广告牌 Uniform。
    BillboardUniform { transform }
}
